package com.css.zfzx.fxpg.common.utils;

import com.linuxense.javadbf.DBFReader;
import org.apache.commons.lang3.StringUtils;
import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;
import org.geotools.data.FileDataStore;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.referencing.CRS;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.filter.Filter;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.crs.CoordinateReferenceSystem;

import java.io.*;
import java.nio.charset.Charset;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class VectorDataUtil {

    public static String readPRJ(String path) {
        StringBuffer result = new StringBuffer();
        File file = new File(path);
        if (!file.exists()) return "";
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new FileReader(file));
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                result.append(tempString);
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result.toString();
    }


    /*********************************DBF*************************************/

    public static String[] getFieldName(String path, String charsetName) throws IOException {
        DBFReader dbfReader = new DBFReader(new FileInputStream(path), Charset.forName(charsetName));
        int fieldCount = dbfReader.getFieldCount();//获取字段数量
        String[] fieldName = new String[fieldCount];
        for (int i = 0; i < fieldCount; i++) {
            fieldName[i] = dbfReader.getField(i).getName();
        }
        dbfReader.close();
        return fieldName;
    }

    public static ArrayList<Object[]> getFieldValue(String path, String charsetName) throws IOException {
        ArrayList<Object[]> result = new ArrayList<Object[]>();
        DBFReader dbfReader = new DBFReader(new FileInputStream(path), Charset.forName(charsetName));
        Object[] rowValues;
        while ((rowValues = dbfReader.nextRecord()) != null) {
            result.add(rowValues);
        }
        dbfReader.close();
        return result;
    }

    public static SimpleFeatureCollection readDBF(String path) {
        return readShp(path, null);
    }

    public static SimpleFeatureCollection readDBF(String path, Filter filter) {
        SimpleFeatureSource featureSource = readStoreByDBF(path);
        if (featureSource == null) return null;
        try {
            return filter != null ? featureSource.getFeatures(filter) : featureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static SimpleFeatureSource readStoreByDBF(String path) {
        File file = new File(path);
        FileDataStore store;
        SimpleFeatureSource featureSource = null;
        try {
            store = FileDataStoreFinder.getDataStore(file);
            ((ShapefileDataStore) store).setCharset(Charset.forName("GBK"));
            featureSource = store.getFeatureSource();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return featureSource;
    }

    /*********************************DBF*********END****************************/


    /*********************************SHP*************************************/

    public static List<List<Object>> readSHPFile(String path, String codeType) {
        String prjPath = path.substring(0, path.length() - 4) + ".prj";
        String strWKTMercator = readPRJ(prjPath);
        boolean isReverse = isReverse(strWKTMercator);
        if (strWKTMercator != "") ProjectTransUtil.setStrWKTMercator(strWKTMercator);
        String lonLatStr = "", wkt = "";
        SimpleFeatureCollection colls1 = readShp(path, codeType);
        SimpleFeatureIterator iters = colls1.features();
        List<List<Object>> result = new ArrayList<List<Object>>();
        while (iters.hasNext()) {
            SimpleFeature sf = iters.next();
            List<Object> attributes = sf.getAttributes();
            wkt = attributes.get(0).toString();
            if (isReverse) {
                if (wkt.indexOf("MULTIPOINT") != -1) {
                    lonLatStr = reverseWktMultiPoint(ProjectTransUtil.wkt2lonLat(wkt));
                } else if (wkt.indexOf("POINT") != -1) {
                    lonLatStr = reverseWktPoint(ProjectTransUtil.wkt2lonLat(wkt));
                } else if (wkt.indexOf("MULTIPOLYGON") != -1) {
                    lonLatStr = reverseWktMultiPolygon(ProjectTransUtil.wkt2lonLat(wkt));
                } else if (wkt.indexOf("POLYGON") != -1) {
                    lonLatStr = reverseWktPolygon(ProjectTransUtil.wkt2lonLat(wkt));
                }
            } else {
                if (wkt.indexOf("MULTIPOINT") != -1) {
                    lonLatStr = ProjectTransUtil.wkt2lonLat(wkt);
                } else if (wkt.indexOf("POINT") != -1) {
                    lonLatStr = ProjectTransUtil.wkt2lonLat(wkt);
                } else if (wkt.indexOf("MULTIPOLYGON") != -1) {
                    lonLatStr = ProjectTransUtil.wkt2lonLat(wkt);
                } else if (wkt.indexOf("POLYGON") != -1) {
                    lonLatStr = ProjectTransUtil.wkt2lonLat(wkt);
                }
            }
            attributes.set(0, lonLatStr);
            result.add(attributes);
        }
        iters.close();
        return result;
    }

    public static SimpleFeatureCollection readShp(String path, String codeType) {
        return readShp(path, null, codeType);
    }

    public static SimpleFeatureCollection readShp(String path, Filter filter, String codeType) {
        SimpleFeatureSource featureSource = readStoreByShp(path, codeType);
        if (featureSource == null) return null;
        try {
            return filter != null ? featureSource.getFeatures(filter) : featureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static SimpleFeatureSource readStoreByShp(String path, String codeType) {
        File file = new File(path);
        FileDataStore store;
        SimpleFeatureSource featureSource = null;
        try {
            store = FileDataStoreFinder.getDataStore(file);
            ((ShapefileDataStore) store).setCharset(Charset.forName(codeType));
            featureSource = store.getFeatureSource();
            store.dispose();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return featureSource;
    }
    /*********************************SHP*********END****************************/

    public static List<List<Object>> readSHPFile2(File file) {
        /*
        String path = file.getName();
        String prjPath = path.substring(0, path.length() - 4) + ".prj";
        String strWKTMercator = readPRJ(prjPath);
        if (strWKTMercator != "") ProjectTransUtil.setStrWKTMercator(strWKTMercator);
         */
        SimpleFeatureCollection colls1 = readShp2(file);
        SimpleFeatureIterator iters = colls1.features();
        List<List<Object>> result = new ArrayList<List<Object>>();
        while (iters.hasNext()) {
            SimpleFeature sf = iters.next();
            List<Object> attributes = sf.getAttributes();
            String lonlatStr = ProjectTransUtil.wkt2lonLat(attributes.get(0).toString());
            attributes.set(0, lonlatStr);
            result.add(attributes);
        }
        return result;
    }
    public static SimpleFeatureCollection readShp2(File file) {
        return readShp2(file, null);
    }
    public static SimpleFeatureCollection readShp2(File file, Filter filter) {
        SimpleFeatureSource featureSource = readStoreByShp2(file);
        if (featureSource == null) return null;
        try {
            return filter != null ? featureSource.getFeatures(filter) : featureSource.getFeatures();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
    public static SimpleFeatureSource readStoreByShp2(File file) {
        FileDataStore store;
        SimpleFeatureSource featureSource = null;
        try {
            store = FileDataStoreFinder.getDataStore(file);
            ((ShapefileDataStore) store).setCharset(Charset.forName("GBK"));
            featureSource = store.getFeatureSource();
            store.dispose();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return featureSource;
    }

    public static void inputStreamToFile(InputStream ins, File file, int len) {
        try {
            OutputStream os = new FileOutputStream(file);
            int bytesRead = 0;
            byte[] buffer = new byte[len];
            while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            ins.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static boolean checkCGCS2000(String path, String type) {
        String name = "";
        if (type != null && type.equals("tif")) {
            gdal.AllRegister();
            Dataset dataset = gdal.Open(path, gdalconstConstants.GA_ReadOnly);
            if (dataset == null) return false;
            name = dataset.GetProjection();
            dataset.delete();
            gdal.GDALDestroyDriverManager();
        } else {
            String prjPath = path.substring(0, path.length() - 4) + ".prj";
            String strWKTMercator = readPRJ(prjPath);
            if (strWKTMercator == "") return false;
            CoordinateReferenceSystem sourceTarget = null;
            try {
                sourceTarget = CRS.parseWKT(strWKTMercator);
            } catch (FactoryException e) {
                e.printStackTrace();
                System.out.println(path + ": 解析错误!");
            }
            name = sourceTarget.getName().toString();
        }
        if (name.indexOf("CGCS2000") != -1 || name.indexOf("cgcs2000") != -1 || name.indexOf("Geodetic_Coordinate_System_2000") != -1 ||
                name.indexOf("Geodetic Coordinate System 2000") != -1) return true;
        return false;
    }

    public static String reverseWktMultiPolygon(String wktPolygon) {
        String oldWkt = wktPolygon;
        oldWkt = oldWkt.substring(oldWkt.indexOf("(((") + 3, oldWkt.lastIndexOf(")))"));
        oldWkt = oldWkt.replace(")), ((", "|");
        oldWkt = oldWkt.replace("), (", "#");

        String wktPolygon1 = "(";
        String[] polygon1 = StringUtils.split (oldWkt, "|");
        for (int i = 0; i < polygon1.length; i++) {
            String[] polygon2 = StringUtils.split (polygon1[i], "#");
            for (int j = 0; j < polygon2.length; j++) {
                String wktPolygon2 = "(";
                String[] coords = polygon2[j].split(", ");
                for (int k = 0; k < coords.length; k++) {
                    String[] lonLat = coords[k].split(" ");
                    String lon = lonLat[1];
                    String lat = lonLat[0];
                    wktPolygon2 += lon + " " + lat + ", ";
                }
                wktPolygon2 = wktPolygon2.substring(0, wktPolygon2.length() - 2) + "), ";
                wktPolygon1 += wktPolygon2;
            }
            wktPolygon1 = wktPolygon1.substring(0, wktPolygon1.length() - 2) + "), ";
        }
        wktPolygon1 = wktPolygon1.substring(0, wktPolygon1.length() - 2);
        return "MULTIPOLYGON (" + wktPolygon1 + ")";
    }

    public static String reverseWktPolygon(String wktPolygon) {
        String oldWkt = wktPolygon;
        oldWkt = oldWkt.substring(oldWkt.indexOf("(") + 2, oldWkt.lastIndexOf("))"));

        String polygonWkt = "Polygon (", coordinate = "";
        String sp = oldWkt.indexOf("),(") != -1 ? "),(" : (oldWkt.indexOf("), (") != -1 ? "), (" : "");
        if ("".equals(sp)) {
            coordinate = "(";
            String[] coordinates = oldWkt.split(",");
            for (int i = 0; i < coordinates.length; i++) {
                String[] coords = coordinates[i].split(" ");
                coordinate += coords[1] + " " + coords[0] + ",";
            }
            coordinate = coordinate.substring(0, coordinate.length() - 1) + ")";
            polygonWkt += coordinate + ")";
        } else {
            oldWkt = oldWkt.replace(sp, "#"); sp = "#";
            String[] coordinates = oldWkt.split(sp);
            for (int i = 0; i < coordinates.length; i++) {
                coordinate = coordinates[i];
                String _coordinates = "(";
                String[] coords = coordinate.split(","), _coords = null;
                for (int j = 0; j < coords.length; j++) {
                    _coords = coords[j].split(" ");
                    _coordinates += _coords[1] + " " + _coords[0] + ",";
                }
                _coordinates = _coordinates.substring(0, _coordinates.length() - 1) + ")";
                polygonWkt += _coordinates + ",";
            }
            polygonWkt += polygonWkt.substring(0, polygonWkt.length() - 1) + ")";
        }
        return polygonWkt;
    }

    public static String reverseWktPoint(String wktPoint) {
        String oldWkt = wktPoint;
        oldWkt = oldWkt.substring(oldWkt.indexOf("(") + 1, oldWkt.lastIndexOf(")"));
        String[] coords = oldWkt.split(" ");
        return "POINT (" + coords[1] + " " + coords[0] + ")";
    }

    public static String reverseWktMultiPoint(String wktMultiPoint) {
        String oldWkt = wktMultiPoint;
        oldWkt = oldWkt.substring(oldWkt.indexOf("(") + 2, oldWkt.lastIndexOf(")") - 1);
        String sp = oldWkt.indexOf("),(") != -1 ? "),(" : (oldWkt.indexOf("), (") != -1 ? "), (" : "");
        String[] coordinates = StringUtils.split(oldWkt, sp);
        String newWkt = "MULTIPOINT (", coordinate = "";
        String[] coords = null;
        for (int i = 0; i < coordinates.length; i++) {
            coordinate = coordinates[i];
            coords = coordinate.split(" ");
            //newWkt += "(" + coords[1] + " " + coords[0] + "),";
            newWkt += coords[1] + " " + coords[0] + ",";
        }
        newWkt = newWkt.substring(0, newWkt.length() - 1) + ")";
        return newWkt;
    }

    public static int judgeIsHaveMsssyCode(List<List<Object>> list) {
        String str = "";
        for (int i = 0; i < list.size(); i++) {
            List<Object> values = list.get(i);
            for (int j = 0; j < values.size(); j++) {
                str = values.get(j).toString();
                if (isHaveMsssyCode(str)) return i;
            }
        }
        return -1;
    }
    private static boolean isHaveMsssyCode(String str) {
        for (int i = 0; i < str.length() / 2; i++) {
                /*if(=="#"){
                    continue;
                }*/
            char c = str.charAt(i);
            // 当从Unicode编码向某个字符集转换时，如果在该字符集中没有对应的编码，则得到0x3f（即问号字符?）
            //从其他字符集向Unicode编码转换时，如果这个二进制数在该字符集中没有标识任何的字符，则得到的结果是0xfffd
            if ((int) c == 0xfffd) {
                // 存在乱码
                return true;
            }
        }
        return false;
    }

    public static String getValueByTIF(String tifFileName) {
        gdal.AllRegister();

        Dataset dataset = gdal.Open(tifFileName, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return null;

        Band band = dataset.GetRasterBand(1);

        int xSize = dataset.getRasterXSize();
        int ySize = dataset.getRasterYSize();

        StringBuilder sb = new StringBuilder();
        double total = 0;
        int buf[] = new int[xSize];
        for(int i = 0; i < ySize; i++) {
            band.ReadRaster(0, i, xSize, 1, buf);
            for(int j = 0; j < xSize; j++) {
                if(/*buf[j] != -2147483648*/buf[j] >= 0) {
                    sb.append(buf[j] + "|");
                    total += buf[j];
                }
            }
        }
        dataset.delete();
        gdal.GDALDestroyDriverManager();
        sb.append(total);
        return sb.toString();
    }
    public static int getRiskLevelByTIFValue(double value, String type) {//type: 0: 直接经济损失等级图 1: 死亡人口等级图
        if ("0".equals(type)) {//0: 直接经济损失等级图
            if (value >= 0.01) {
                return 1;
            } else if (value >= 0.002 && value < 0.01) {
                return 2;
            } else if (value >= 0.001 && value < 0.002) {
                return 3;
            } else if (value >= 0.0003 && value < 0.001) {
                return 4;
            } else if (value < 0.0003) {
                return 5;
            }
        } else if ("1".equals(type)) {//1: 死亡人口等级图
            if (value >= 500) {
                return 1;
            } else if (value >= 100 && value < 500) {
                return 2;
            } else if (value >= 50 && value < 100) {
                return 3;
            } else if (value > 0 && value < 50) {
                return 4;
            }
        }
        return -1;
    }

    public static String getRectsByTIF(String tifFileName) {
        gdal.AllRegister();

        Dataset dataset = gdal.Open(tifFileName, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) return null;

        Band band = dataset.GetRasterBand(1);

        int xSize = dataset.getRasterXSize();
        int ySize = dataset.getRasterYSize();

        //六参数信息
        double[] geoTransform = dataset.GetGeoTransform();
        //影像左上角投影坐标
        double[] luCoordinate = new double[2];
        luCoordinate[0] = geoTransform[0];
        luCoordinate[1] = geoTransform[3];

        int buf[] = new int[xSize];
        String coordinate = "";
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < ySize; i++) {
            band.ReadRaster(0, i, xSize, 1, buf);
            for(int j = 0; j < xSize; j++) {
                if(buf[j] < 0) continue;
                double luLon = geoTransform[0] + j * geoTransform[1] + i * geoTransform[2];
                double luLat = geoTransform[3] + j * geoTransform[4] + i * geoTransform[5];

                double ruLon = geoTransform[0] + (j + 1) * geoTransform[1] + i * geoTransform[2];
                double ruLat = geoTransform[3] + (j + 1) * geoTransform[4] + i * geoTransform[5];

                double rbLon = geoTransform[0] + (j + 1) * geoTransform[1] + (i + 1) * geoTransform[2];
                double rbLat = geoTransform[3] + (j + 1) * geoTransform[4] + (i + 1) * geoTransform[5];

                double lbLon = geoTransform[0] + j * geoTransform[1] + (i + 1) * geoTransform[2];
                double lbLat = geoTransform[3] + j * geoTransform[4] + (i + 1) * geoTransform[5];

                coordinate = luLon + " " + luLat + ";" + ruLon + " " + ruLat + ";" + rbLon + " " + rbLat + ";" + lbLon + " " + lbLat + "|";
                sb.append(coordinate);
            }
        }
        coordinate = sb.toString();
        coordinate = coordinate.substring(0, coordinate.length() - 1);
        dataset.delete();
        gdal.GDALDestroyDriverManager();
        return coordinate;
    }

    //校验字段空值
    public static boolean checkValueIsBlank(List<List<Object>> list) {
        String value = "";
        for (int i = 0; i < list.size(); i++) {
            List<Object> attributes = list.get(i);
            for (int j = 0; j < attributes.size(); j++) {
                value = attributes.get(j).toString();
                if (value == null || "".equals(value.trim())) return false;
            }
        }
        return true;
    }

    //是否为阿拉伯数字
    public static boolean checkLevel(List<List<Object>> list) {
        String arab = "1 2 3 4 5", level = "";
        for (int i = 0; i < list.size(); i++) {
            List<Object> values = list.get(i);
            level = values.get(1).toString();
            if (arab.indexOf(level) == -1) return false;
        }
        return true;
    }

    public static String getFormatDate() {
        //SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
        return df.format(new Date());
    }

    private static boolean isReverse (String strWKTMercator) {
        CoordinateReferenceSystem sourceTarget = null;
        try {
            sourceTarget = CRS.parseWKT(strWKTMercator);
        } catch (FactoryException e) {
            e.printStackTrace();
        }
        String longitude = sourceTarget.getCoordinateSystem().getAxis(0).getName().toString(),
                latitude = sourceTarget.getCoordinateSystem().getAxis(1).getName().toString();
        if ("longitude".equals(longitude.toLowerCase()) && "latitude".equals(latitude.toLowerCase())) return true;
        return false;
    }
}
